#include "EventLoop.h"



CEventLoop :: CEventLoop()
{
   epoll_max_events = 1000;
   epollfd = epoll_create(epoll_max_events);
   eventList = new struct epoll_event[epoll_max_events]();
   
}

CEventLoop :: CEventLoop(int maxeventnum)
{
   epoll_max_events = maxeventnum;
   epollfd = epoll_create(maxeventnum);
   eventList = new struct epoll_event[epoll_max_events]();
   
}

CEventLoop :: ~CEventLoop()
{
   for(int i = 0; i < epoll_max_events; i++)
      close(eventList[i].data.fd);
   eventCbList.clear();
   close(epollfd);
}

int CEventLoop :: EventRegister(int fd, ... )
{
    va_list vl;
    va_start(vl, fd);
    CNullClass *thisp =  va_arg(vl, CNullClass*);
    CallbackFunc cfunc = va_arg(vl, CallbackFunc);
    void *data = va_arg(vl, void *);
    va_end(vl);
    CBEvent tempevent;
    tempevent.data = data;
    tempevent.func = cfunc;
    tempevent.thisp = thisp;
    eventCbList[fd] = tempevent;

    //添加事件
    struct epoll_event event =  {0};
    event.events = EPOLLIN;//|EPOLLET;
    event.data.fd = fd;
    if(epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event) < 0)
    {
        MY_ERROR_LOG("epoll add failed fd: %d \n", fd);
        return -1;
    }
    else
        MY_ERROR_LOG("epoll fd : %d add successed\n", fd);
    return 0;


}


int CEventLoop :: EventUnRegister(int fd)
{
    eventCbList.erase(eventCbList.find(fd));
    struct epoll_event event = {0};
    event.events = EPOLLIN|EPOLLET;
    event.data.fd = fd;
    if(epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &event) < 0)
      {
         MY_ERROR_LOG("epoll del failed fd: %d\n", fd);
         return -1;
      }
    close(fd);
    return 0;
}


int CEventLoop :: EventSchedule(int timeout)
{
    int ret = epoll_wait(epollfd, eventList, epoll_max_events, timeout);
    if(ret < 0)
    {
         MY_ERROR_LOG("epoll error\n");
         return -1;
    }
    else if(ret == 0)
         return 0;
        
    //处理事件
    for(int i = 0; i < ret; i++)
    {
        if(eventList[i].events & EPOLLERR || (eventList[i].events & EPOLLHUP) || !(eventList[i].events & EPOLLIN))
        {
           MY_ERROR_LOG("epoll error\n");
           close(eventList[i].data.fd);
           return -1;
        }
        //找到回调进行执行
        if(eventCbList.find(eventList[i].data.fd) != eventCbList.end())
        {
            CNullClass *pthis = eventCbList[eventList[i].data.fd].thisp;
            CallbackFunc cb = eventCbList[eventList[i].data.fd].func;
            void *data = eventCbList[eventList[i].data.fd].data;
            (pthis->*cb)(eventList[i].data.fd, data); 
        }
        else
            MY_ERROR_LOG("eventCbList no find monitor fd %d\n", eventList[i].data.fd);

    }
    return 0;
}



void CEventLoop :: EventSetNoBlock(int fd)
{
    int opts;  
    opts=fcntl(fd,F_GETFL);  
      
    if(opts<0)  
    {  
        MY_ERROR_LOG("fcntl(sock,GETFL)");  
        return; 
    }  
      
    opts = opts|O_NONBLOCK;  
      
    if(fcntl(fd,F_SETFL,opts)<0)  
    {  
        MY_ERROR_LOG("fcntl(sock,SETFL,opts)");  
        return; 
    }    
}
